
#include "lib_alsa.h"

//****************************************************************
static int alsa_size = 0;
static snd_pcm_t *        alsa_handle = NULL;
static snd_pcm_status_t * pcm_status  = NULL;

static int alsa_sample_rate = 0;
static int alsa_channels	= 0;
static int alsa_sample_fmt	= 0;
static int alsa_cfg_once	= 0;
//****************************************************************

int alsa_pcm_buff_clear(void)
{
	int ret  = -1;
	
	if(!alsa_handle)
		return -1;

	ret = snd_pcm_drop(alsa_handle);
	if(ret < 0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	ret = snd_pcm_prepare(alsa_handle);
	if(ret < 0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	return 0;
}


int alsa_pcm_get_status(void)
{
	int ret = -1;
	
	long delay = 0;
	unsigned long avail = 0;
	unsigned long avail_max = 0;

	if(!alsa_handle){
		return 0;
	}
	
	if(!pcm_status){
		return 0;
	}

	ret = snd_pcm_status(alsa_handle,pcm_status);
	if(ret < 0){
		return 0;
	}
	
    avail     = snd_pcm_status_get_avail(pcm_status);
    delay     = snd_pcm_status_get_delay(pcm_status);
	avail_max = snd_pcm_status_get_avail_max(pcm_status);

	log_n("avail: %d:%d:%d\n", avail,delay,avail_max);

	if(!delay){
		return 1;
	}
	else{
		return delay;
	}
	
	return 0;
}

int alsa_pcm_play_data(uint8_t * data,int size)
{
	int ret  = -1;
	
	//*******************************************************************************
	if(!alsa_handle)
		return -1;
	//*******************************************************************************

	ret = snd_pcm_writei(alsa_handle, data, size);
	if(ret < 0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		ret = snd_pcm_recover(alsa_handle,ret,0);
		if(ret < 0){
			log_e("err=%d,%s\n",ret,snd_strerror(ret));
			return -1;
		}
		
		ret = snd_pcm_writei(alsa_handle, data, size);
		if(ret < 0){
			log_e("err=%d,%s\n",ret,snd_strerror(ret));
		}	
	}
	//*******************************************************************************

	return 0;
}





int alsa_cfg_play_path(int volume)//0-6
{
	int ret  = -1;

	snd_hctl_t *pt_hctl=NULL;
	snd_hctl_elem_t *pt_helem=NULL;

	snd_ctl_elem_id_t *pt_id =NULL;
	snd_ctl_elem_value_t *pt_value =NULL;
	
	//****************************************************
	snd_ctl_elem_id_alloca(&pt_id);
	snd_ctl_elem_value_alloca(&pt_value);

	ret = snd_hctl_open(&pt_hctl, ALSA_HCTL_NAME, 0);
	if(ret<0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	snd_hctl_load(pt_hctl);
	snd_ctl_ascii_elem_id_parse(pt_id, ALSA_HCTL_ELEM_PATH);

	pt_helem = snd_hctl_find_elem(pt_hctl, pt_id);
	snd_hctl_elem_read(pt_helem, pt_value);

	snd_ctl_elem_value_get_integer(pt_value, 0);
	snd_ctl_elem_value_get_integer(pt_value, 1);

	snd_ctl_elem_value_set_integer(pt_value, 0, volume);
	snd_hctl_elem_write(pt_helem, pt_value);

	if(pt_hctl){
		snd_hctl_close(pt_hctl);
		pt_hctl = NULL;
	}

	return 0;
}



int alsa_cfg_play_vol(int volume)//0-100
{
	int ret = -1;

	snd_hctl_t *pt_hctl=NULL;
	snd_hctl_elem_t *pt_helem=NULL;

	snd_ctl_elem_id_t *pt_id =NULL;
	snd_ctl_elem_value_t *pt_value =NULL;

	//****************************************************
	snd_ctl_elem_id_alloca(&pt_id);
	snd_ctl_elem_value_alloca(&pt_value);

	ret = snd_hctl_open(&pt_hctl, ALSA_HCTL_NAME, 0);
	if(ret<0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	snd_hctl_load(pt_hctl);
	snd_ctl_ascii_elem_id_parse(pt_id, ALSA_HCTL_ELEM_NAME);

	pt_helem = snd_hctl_find_elem(pt_hctl, pt_id);
	snd_hctl_elem_read(pt_helem, pt_value);

	snd_ctl_elem_value_get_integer(pt_value, 0);
	snd_ctl_elem_value_get_integer(pt_value, 1);

	snd_ctl_elem_value_set_integer(pt_value, 0, volume*255/100);//volume*255/100
	snd_ctl_elem_value_set_integer(pt_value, 1, volume*255/100);

	snd_hctl_elem_write(pt_helem, pt_value);

	if(pt_hctl){
		snd_hctl_close(pt_hctl);
		pt_hctl = NULL;
	}

	return 0;
}


int alsa_cfg_device(void)
{
	int ret = -1;
	int sample_rate = 0;
	int channels	= 0;
	int sample_fmt	= 0;
	int dir         = 0;

	snd_pcm_hw_params_t *hw_params = NULL;

	if(alsa_cfg_once)
		return -1;

	if(!alsa_handle)
		return -1;

	//如果需要非阻塞方式，则将第二个参数，设置为1。
	//snd_pcm_open后，默认为阻塞方式，因此，该接口可以不用调用。

	//snd_pcm_nonblock(alsa_handle,1);

	ret = snd_pcm_hw_params_malloc(&hw_params);
	if(ret<0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	snd_pcm_hw_params_any(alsa_handle, hw_params);
	snd_pcm_hw_params_set_access(alsa_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);

	sample_fmt = alsa_sample_fmt;//SND_PCM_FORMAT_S8;//SND_PCM_FORMAT_S16_LE
	snd_pcm_hw_params_set_format (alsa_handle, hw_params, sample_fmt);

	sample_rate = alsa_sample_rate;//44100;//44100;//48000
	snd_pcm_hw_params_set_rate_near(alsa_handle, hw_params, &sample_rate, &dir);

	channels = alsa_channels;//2;
	snd_pcm_hw_params_set_channels(alsa_handle, hw_params, channels);

	snd_pcm_hw_params(alsa_handle, hw_params);

	snd_pcm_hw_params_get_period_size(hw_params, &alsa_size, 0);
	snd_pcm_hw_params_free(hw_params);

	ret = snd_pcm_prepare(alsa_handle);
	if(ret < 0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
		return -1;
	}

	log_d("alsa config device succeed.\n");

	alsa_cfg_once = 1;

	return 0;
}

int alsa_cfg_sample_fmt(int fmt)
{
	if(fmt == 1)
	{
		fmt = SND_PCM_FORMAT_S16_LE;
	}

	if(fmt == 8)
	{
		fmt = SND_PCM_FORMAT_S8;
	}

	alsa_sample_fmt = fmt;
	
	return 0;
}

int alsa_cfg_sample_rate(int sample_rate)
{
	alsa_sample_rate = sample_rate;
	return 0;
}

int alsa_cfg_channels(int channels)
{
	alsa_channels = channels;
	return 0;
}


int lib_alsa_init(void)
{
	int ret = -1;

	//hw:0,0 //rockchiprk809
	//hw:1,0 //rockchiphdmi
	ret = snd_pcm_open(&alsa_handle, "hw:0,0", SND_PCM_STREAM_PLAYBACK, 0);
    if(ret < 0){
		log_e("err=%d,%s\n",ret,snd_strerror(ret));
        return -1;
    }

	alsa_cfg_once = 0;
	snd_pcm_status_malloc(&pcm_status);
	//**********************************************************
	
	alsa_cfg_play_path(6);
	alsa_cfg_play_vol(75);
	//**********************************************************

	return 0;
}


int lib_alsa_deinit(void)
{
	log_n("lib alsa exit.\n");

	if(pcm_status){
		snd_pcm_status_free(pcm_status);
		pcm_status = NULL;
	}

	if(alsa_handle){
		snd_pcm_close(alsa_handle);
		alsa_handle = NULL;
	}

	
	return 0;
}
